Skip to content

淺談 Git 資料結構

TLDR

  • Git 的所有資料與版本控制紀錄皆儲存在 .git 目錄中,刪除該目錄即等同刪除本機版控。
  • objects 資料夾以 SHA-1 哈希值儲存 Blob(檔案內容)、Tree(目錄結構)與 Commit(提交資訊)三種物件。
  • refs 資料夾儲存分支與 Tag 的指標,它們本質上只是指向特定 Commit HASH 的檔案。
  • logs 資料夾記錄了 HEAD 與分支的變動歷史,可透過 git reflog 查詢並用於還原誤刪的 Commit。
  • index 檔案為二進位檔,記錄了 git add 後的暫存區快照。
  • HEAD 檔案記錄當前工作目錄所處的分支或 Commit 位置。
  • 分支與 Tag 僅是指向 Commit 的指標,Git 的歷史紀錄是透過 Commit 物件中的指標鏈(指向前一個 Commit)所構成。

.git 目錄結構解析

Git 的所有儲存資料都存在於 .git 資料夾裡。以下為該目錄下各核心元件的用途與運作機制。

資料夾結構

  • hooks:存放各種客製化腳本,在 Git 操作(如 commitpushmerge)的特定時機自動執行,適用於自動化測試或檢查程式碼風格。
  • info:儲存輔助性資訊,其中 exclude 檔案用於定義本機排除規則,與 .gitignore 用途相同,但僅適用於單一開發者環境。
  • logs:記錄引用(如 branch、HEAD)的更新歷史。
    • 什麼情況下會遇到這個問題:當執行 git reset --hardgit rebase -i 導致 Commit 記錄遺失時,可透過 git reflog 讀取此處紀錄並進行還原。
  • objects:儲存所有 Git 資料物件(Blob、Tree、Commit)。
    • 結構:以 SHA-1 哈希值前兩個字元作為目錄,後 38 個字元作為檔案名稱。
    • 物件生成機制:執行 Commit 時會產生三種物件:
      • Blob 物件:儲存檔案的實際內容。
      • Tree 物件:儲存目錄結構與對應的 Blob 物件哈希值。
      • Commit 物件:儲存提交資訊(包含 Tree 哈希、上一個 Commit 哈希、作者與訊息)。
  • refs:儲存分支與 Tag 的指標。
    • heads:儲存本機分支。
    • remotes:儲存遠端分支。
    • tags:儲存 Tag 名稱。

關鍵檔案說明

  • COMMIT_EDITMSG:記錄上一次 Commit 的訊息。執行 git commitgit commit --amend 時會開啟此檔案供編輯。
  • config:儲存該儲存庫的專屬 Git 設定。
  • index:二進位檔案,記錄最新一次 Commit 後的快照及 git add 加入的檔案資訊。
  • HEAD:記錄當前檢出的分支或 Commit。若指向分支,內容為 ref: refs/heads/分支名;若處於分離 HEAD 狀態,則直接儲存 Commit HASH。
  • ORIG_HEAD:儲存執行 git resetgit merge 等破壞性操作前的 HEAD 狀態,用於還原。
  • FETCH_HEAD:標註每次 git fetch 的紀錄,格式如下:
    text
    {Commit SHA-1} [not-for-merge] branch '{分支名稱}' of {遠端儲存庫網址}
    • 什麼情況下會遇到這個問題:當 git fetch 執行後,若未觸發 Merge 行為,該節點會標記為 [not-for-merge]

分支與版本控制的本質

由 Git 的資料結構可知,分支與 Tag 本質上僅是指向特定 Commit 物件的指標。

  • 分支 (Branch):隨每次 Commit 自動更新指向的指標。
  • 標籤 (Tag):指向固定 Commit 物件的指標。

Git 的歷史紀錄是透過 Commit 物件內部儲存的「上一個 Commit HASH」鏈結而成。當執行 git resetgit rebase 時,雖然分支指標移動了,但舊的 Commit 物件依然存在於 objects 資料夾中,這也是為什麼透過 git reflog 可以找回歷史紀錄的原因。


異動歷程

    • 初版文件建立。
    • 儲存庫根目錄底下的「.gitconfig」無法生效,所以移除可作為版控的相關描述。